#region Copyright (c) 2006-2009 Widgetsphere LLC, All Rights Reserved
//--------------------------------------------------------------------- *
//                          Widgetsphere  LLC                           *
//             Copyright (c) 2006-2009 All Rights reserved              *
//                                                                      *
//                                                                      *
//This file and its contents are protected by United States and         *
//International copyright laws.  Unauthorized reproduction and/or       *
//distribution of all or any portion of the code contained herein       *
//is strictly prohibited and will result in severe civil and criminal   *
//penalties.  Any violations of this copyright will be prosecuted       *
//to the fullest extent possible under law.                             *
//                                                                      *
//THE SOURCE CODE CONTAINED HEREIN AND IN RELATED FILES IS PROVIDED     *
//TO THE REGISTERED DEVELOPER FOR THE PURPOSES OF EDUCATION AND         *
//TROUBLESHOOTING. UNDER NO CIRCUMSTANCES MAY ANY PORTION OF THE SOURCE *
//CODE BE DISTRIBUTED, DISCLOSED OR OTHERWISE MADE AVAILABLE TO ANY     *
//THIRD PARTY WITHOUT THE EXPRESS WRITTEN CONSENT OF WIDGETSPHERE LLC   *
//                                                                      *
//UNDER NO CIRCUMSTANCES MAY THE SOURCE CODE BE USED IN WHOLE OR IN     *
//PART, AS THE BASIS FOR CREATING A PRODUCT THAT PROVIDES THE SAME, OR  *
//SUBSTANTIALLY THE SAME, FUNCTIONALITY AS ANY WIDGETSPHERE PRODUCT.    *
//                                                                      *
//THE REGISTERED DEVELOPER ACKNOWLEDGES THAT THIS SOURCE CODE           *
//CONTAINS VALUABLE AND PROPRIETARY TRADE SECRETS OF WIDGETSPHERE,      *
//INC.  THE REGISTERED DEVELOPER AGREES TO EXPEND EVERY EFFORT TO       *
//INSURE ITS CONFIDENTIALITY.                                           *
//                                                                      *
//THE END USER LICENSE AGREEMENT (EULA) ACCOMPANYING THE PRODUCT        *
//PERMITS THE REGISTERED DEVELOPER TO REDISTRIBUTE THE PRODUCT IN       *
//EXECUTABLE FORM ONLY IN SUPPORT OF APPLICATIONS WRITTEN USING         *
//THE PRODUCT.  IT DOES NOT PROVIDE ANY RIGHTS REGARDING THE            *
//SOURCE CODE CONTAINED HEREIN.                                         *
//                                                                      *
//THIS COPYRIGHT NOTICE MAY NOT BE REMOVED FROM THIS FILE.              *
//--------------------------------------------------------------------- *
#endregion
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Xml;
using System.Diagnostics;

namespace Widgetsphere.GeneratorEngine
{
	public class Generator
	{
		#region Class Members

		protected string _destinationPath = "";		
		protected string _folderKey = Guid.NewGuid().ToString();
		protected List<string> _includeFileList = new List<string>();
		protected string _csharpCompilerPath = @"C:\WINDOWS\Microsoft.NET\Framework\v3.5\csc.exe";
		protected List<IFileTemplate> _generatorList = new List<IFileTemplate>();
		protected string _assemblyName = "";
		protected bool _copySource = false;

		#endregion

		#region Constructor

		public Generator(string destinationPath, string assemblyName)
		{			
			_destinationPath = destinationPath;
			_assemblyName = assemblyName;
		}

		public Generator(string destinationPath, string assemblyName, bool copySource)
			: this(destinationPath, assemblyName)
		{
			_copySource = copySource;
		}

		#endregion

		#region Property Implmentations

		public string DestinationPath
		{
			get { return _destinationPath; }
			set { _destinationPath = value; }
		}

		public List<string> IncludeFileList
		{
			get { return _includeFileList; }
		}

		public string TempFolder
		{
			get
			{
				string retval = System.IO.Path.GetTempPath();
				retval = Path.Combine(retval, _folderKey);
				return retval;
			}
		}

		public string CSharpCompilerPath
		{
			get { return _csharpCompilerPath; }
			set { _csharpCompilerPath = value; }
		}

		public List<IFileTemplate> GeneratorList
		{
			get { return _generatorList; }
		}

		public string AssemblyName
		{
			get { return _assemblyName; }
			set { _assemblyName = value; }
		}

		#endregion

		#region Methods

		//public abstract void GenerateCode(string destinationFolder);

		public virtual void Generate()
		{
			string s = "";
			Generate(true, out s);
		}

		public virtual void Generate(bool deleteSource, out string tempFolder)
		{
			tempFolder = this.TempFolder;
			if (Directory.Exists(this.TempFolder)) Directory.Delete(this.TempFolder, true);
			Directory.CreateDirectory(this.TempFolder);
			if (!Directory.Exists(this.DestinationPath)) Directory.CreateDirectory(this.DestinationPath);
			this.Compile(deleteSource);
		}

		internal string GetCompilationString()
		{
			//string retval =
			//  @" /t:library " +
			//  @" /out:{0}\Reference\" + _folderKey + @".dll /lib:{0}\Reference /r:""C:\WINDOWS\Microsoft.NET\Framework\v3.0\Windows Communication Foundation\System.ServiceModel.dll"" /r:""C:\WINDOWS\Microsoft.NET\Framework\v3.0\Windows Communication Foundation\System.Runtime.Serialization.dll"" /r:CeleriQ.Cloud.API.dll /r:Widgetsphere.Common.dll /debug /recurse:{0}\*.cs";

			string retval =
					@" /doc:{0}\Reference\" + this.AssemblyName + @".xml " +
					@" /t:library " +
					@" /out:{0}\Reference\" + this.AssemblyName + @".dll /lib:{0}\Reference ";

			foreach (string file in this.IncludeFileList)
			{
				FileInfo fi = new FileInfo(file);
				retval += @"/r:""" + fi.Name + @""" ";
			}

			retval += @" /debug /recurse:{0}\*.cs";

			return retval;
		}

		private void Compile(bool deleteSource)
		{
			Directory.CreateDirectory(Path.Combine(this.TempFolder, "Reference"));

			//Copy includes
			foreach (string file in this.IncludeFileList)
			{
				FileInfo fi = new FileInfo(file);
				File.Copy(file, Path.Combine(Path.Combine(this.TempFolder, "Reference"), fi.Name));
			}

			//Create all the files
			foreach (IFileTemplate generator in GeneratorList)
			{
				generator.Generate(this.TempFolder);
			}
			
			//Begin the compilation process
			string compilationString = string.Format(this.GetCompilationString(), "\"" + this.TempFolder + "\"");
			string cscProcessPath = this.CSharpCompilerPath;
			ProcessStartInfo cscProcessInfo = new ProcessStartInfo(this.CSharpCompilerPath);
			cscProcessInfo.CreateNoWindow = true;
			cscProcessInfo.UseShellExecute = false;
			cscProcessInfo.WindowStyle = ProcessWindowStyle.Hidden;
			cscProcessInfo.Arguments = compilationString;
			cscProcessInfo.RedirectStandardOutput = true;

			Process cscProcess = new Process();
			cscProcess.StartInfo = cscProcessInfo;
			cscProcess.Start();
			string compilerOutput = cscProcess.StandardOutput.ReadToEnd();
			cscProcess.StandardOutput.Close();

			cscProcess.WaitForExit(30000);

			if (cscProcess.ExitCode != 0)
			{
				//Remove the temp folder
				if (deleteSource)
					Directory.Delete(this.TempFolder, true);

				throw new CompileException("A compilation error occurred. Detailed output: \n" + compilerOutput);
			}
			else
			{
				string sourceBin = Path.Combine(this.TempFolder, "Reference");
				//string destBin = Path.Combine(_destinationPath, "Reference");
				string destBin = _destinationPath;
				if (!Directory.Exists(_destinationPath)) Directory.CreateDirectory(_destinationPath);
				if (!Directory.Exists(destBin)) Directory.CreateDirectory(destBin);

				if (_copySource)
				{
					CopyDirectory(this.TempFolder, _destinationPath, true);
				}
				else
				{
					string[] fileList = System.IO.Directory.GetFiles(sourceBin, "*.dll");
					foreach (string s in fileList)
					{
						FileInfo fi = new FileInfo(s);
						File.Copy(s, Path.Combine(destBin, fi.Name), true);
					}

					fileList = System.IO.Directory.GetFiles(sourceBin, "*.xml");
					foreach (string s in fileList)
					{
						FileInfo fi = new FileInfo(s);
						File.Copy(s, Path.Combine(destBin, fi.Name), true);
					}

					fileList = System.IO.Directory.GetFiles(sourceBin, "*.pdb");
					foreach (string s in fileList)
					{
						FileInfo fi = new FileInfo(s);
						File.Copy(s, Path.Combine(destBin, fi.Name), true);
					}
				}

				//Remove the temp folder
				if (deleteSource)
					Directory.Delete(this.TempFolder, true);

			}

		}

		private void CopyDirectory(string sourcePath, string destPath, bool overwrite)
		{
			System.IO.DirectoryInfo sourceDir = new System.IO.DirectoryInfo(sourcePath);
			System.IO.DirectoryInfo destDir = new System.IO.DirectoryInfo(destPath);
			if (sourceDir.Exists)
			{
				if (!destDir.Exists)
					destDir.Create();

				foreach (System.IO.FileInfo file in sourceDir.GetFiles())
				{
					if (overwrite)
						file.CopyTo(System.IO.Path.Combine(destDir.FullName, file.Name), true);
					else if ((System.IO.File.Exists(System.IO.Path.Combine(destDir.FullName, file.Name))) == false)
						file.CopyTo(System.IO.Path.Combine(destDir.FullName, file.Name), false);
				}

				foreach (System.IO.DirectoryInfo dir in sourceDir.GetDirectories())
				{
					CopyDirectory(dir.FullName, System.IO.Path.Combine(destDir.FullName, dir.Name), overwrite);
				}
			}
		}

		#endregion

	}
}
